package middleware

import (
	"admin/dao/auth"
	model "admin/models/auth"
	"bytes"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"strconv"
	"time"
)

// ResponseWriterWrapper 定义一个包装器来捕获响应
type ResponseWriterWrapper struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

// Write 重写Write方法来捕获响应体
func (w ResponseWriterWrapper) Write(b []byte) (int, error) {
	w.body.Write(b)
	return w.ResponseWriter.Write(b)
}

// OperationLog 操作日志中间件
func OperationLog() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 记录请求开始时间
		startTime := time.Now()

		// 创建响应体副本以捕获响应
		blw := &ResponseWriterWrapper{
			ResponseWriter: c.Writer,
			body:           &bytes.Buffer{},
		}
		c.Writer = blw

		// 获取请求信息
		ip := c.ClientIP()
		method := c.Request.Method
		path := c.Request.URL.Path
		userAgent := c.Request.UserAgent()

		// 从上下文中获取用户信息
		var userID int64
		var username string
		if uid, exists := c.Get("userID"); exists {
			if uidStr, ok := uid.(string); ok {
				if id, err := strconv.ParseInt(uidStr, 10, 64); err == nil {
					userID = id
				}
			}
		}

		// 处理请求
		c.Next()

		// 计算处理时间
		latency := time.Since(startTime).Milliseconds()

		// 获取状态码
		statusCode := c.Writer.Status()

		// 从上下文中获取数据库连接
		dbValue, exists := c.Get("db")
		if !exists {
			// 如果没有数据库连接，直接返回
			return
		}

		db, ok := dbValue.(*gorm.DB)
		if !ok {
			// 如果数据库连接类型不正确，直接返回
			return
		}

		operationRepo := auth.NewOperationLogRepo(db)

		// 创建操作日志门面实例

		// 创建操作日志记录
		log := &model.OperationLog{
			UserID:     userID,
			Username:   username,
			IP:         ip,
			Method:     method,
			Path:       path,
			UserAgent:  userAgent,
			StatusCode: statusCode,
			Latency:    latency,
			RespData:   blw.body.String(),
		}

		// 异步保存操作日志
		go func() {
			// 忽略一些不需要记录的日志路径
			if path != "/operation-logs" && path != "/operation-logs/" {
				_ = operationRepo.Create(log)
			}
		}()
	}
}
